package cn.dwy2002.task.service;

import com.dwy2002.enums.TaskState;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Map;
import java.util.Set;

/**
 * 任务状态机服务
 *
 * @author 杜伟毅
 * @version 1.0
 * @since 2025/07/17
 */
@Service
public class TaskStateMachine {
    /**
     * 状态转移规则映射表，定义每个任务状态允许转换的目标状态集合。
     * <p>
     * 规则说明：
     * 1. PUBLISHED 可转至 ONGOING 或 CLOSED
     * 2. ONGOING 可转至 WAITING_REVIEW, DELAYED 或 CLOSED
     * 3. WAITING_REVIEW 可转至 COMPLETED 或 ONGOING
     * 4. COMPLETED 仅允许转回 WAITING_REVIEW
     * 5. DELAYED 可转至 ONGOING 或 CLOSED
     * 6. CLOSED 是终态，不允许转换到任何状态
     * </p>
     * <p>
     * 设计说明：
     * - 使用不可变集合确保线程安全
     * - 终态用空集合显式表示
     * </p>
     */
    private static final Map<TaskState, Set<TaskState>> TRANSITION_RULES = Map.of(TaskState.PUBLISHED, Set.of(TaskState.ONGOING, TaskState.CLOSED), TaskState.ONGOING, Set.of(TaskState.WAITING_REVIEW, TaskState.DELAYED, TaskState.CLOSED), TaskState.WAITING_REVIEW, Set.of(TaskState.COMPLETED, TaskState.ONGOING), TaskState.COMPLETED, Set.of(TaskState.WAITING_REVIEW), TaskState.DELAYED, Set.of(TaskState.ONGOING, TaskState.CLOSED), TaskState.CLOSED, Set.of() // 终态不可转换
    );

    /**
     * <p>
     * 使用示例：
     * <pre>{@code
     * if (stateMachine.canTransit(TaskState.ONGOING, TaskState.CLOSED)) {
     * // 允许执行状态变更操作
     * }
     * }</pre>
     * </p>
     * <p>
     * 验证状态转移是否合法
     * <p>
     * 根据预定义的状态转换规则({@link #TRANSITION_RULES})，检查从当前状态转换到目标状态是否被允许。
     * </p>
     *
     * @param current 当前状态(数字)，不可为 null
     * @param target  目标状态(数字)，不可为 null
     * @return 当且仅当存在以下情况时返回 true：
     * - 目标状态在当前状态允许转换的集合中
     * - 当前状态存在于转换规则映射表
     * <p>
     * 以下情况返回 false：
     * - 当前状态是终态(CLOSED)
     * - 状态转换规则未定义当前状态
     * - 目标状态不在允许转换集合中
     * </p>
     * @throws NullPointerException 若任一参数为 null
     * @author 杜伟毅
     * @since 2025/7/17 0017 10:47
     */
    public boolean canTransit(Integer current, Integer target) {
        return TRANSITION_RULES.getOrDefault(TaskState.fromCode(current), Collections.emptySet()).contains(TaskState.fromCode(target));
    }
}
